package com.matrix.framework.core.config;

import com.matrix.framework.core.component.MatrixAuthenticationEntryPoint;
import com.matrix.framework.core.component.MatrixJwtTokenFilter;
import com.matrix.framework.core.component.MatrixReactiveUserDetailsServices;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;


/**
 * Matrix安全配置类
 * 
 * Copyright © 海平面工作室 版权所有
 *
 * @Author: Leo
 * @Create: 2024/10/3 11:15
 * @Since 1.0
 */
@Configuration
@EnableWebFluxSecurity
public class MatrixSecurityConfiguration {

    @Value("${matrix.security.first-login-change-password:false}")
    private boolean firstLoginChangePassword;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(
            ServerHttpSecurity http,
            MatrixReactiveUserDetailsServices userDetailsService,
            MatrixJwtTokenFilter jwtAuthenticationFilter,
            MatrixAuthenticationEntryPoint authenticationEntryPoint) {
        // 定义哪些请求需要认证，哪些不需要
        http
            .csrf(ServerHttpSecurity.CsrfSpec::disable)   // 禁用CSRF(即允许跨域访问)
            .authorizeExchange(authorize -> {
                // 允许所有人访问静态资源
                authorize.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();
                // 允许访问根路径和前端路由（SPA应用需要）
                authorize.pathMatchers("/", "/index.html", "/static/**", "/*.js", "/*.css", "/*.ico","/*.mjs").permitAll();
                // 允许访问前端静态资源
                authorize.pathMatchers("/css/**", "/js/**", "/jse/**", "/assets/**", "/favicon.ico", "/_app.config.js").permitAll();
                // 只允许登录接口无需认证
                authorize.pathMatchers("/auth/login").permitAll();
                // 允许密码修改接口无需认证（首次登录改密码功能）
                authorize.pathMatchers("/auth/change-password").permitAll();
                // 允许全局选项接口（低代码系统需要）
                authorize.pathMatchers("/global/**").permitAll();
                // 允许系统配置获取接口（系统启动时需要）
                authorize.pathMatchers("/sysconfig/value/**").permitAll();
                // 允许获取过期token的测试接口（临时测试用）
                authorize.pathMatchers("/test/jwt/expired-token").permitAll();
                // IP安全管理接口需要管理员权限
                //authorize.pathMatchers("/security/ip/**").hasAnyRole("admin.name.super", "admin.name.sys");
                // 其他请求都需要认证
                authorize.anyExchange().authenticated();
            })
            // 配置认证规则: 去数据库查询用户信息，然后进行认证
            .authenticationManager(new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService))
            // 使用 JWT 验证过滤器
            .securityContextRepository(jwtAuthenticationFilter)
            // 配置异常处理
            .exceptionHandling(exceptions -> exceptions
                // 当认证失败时的处理
                .authenticationEntryPoint(authenticationEntryPoint)
            );
        return http.build();
    }

    @Primary
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 获取首次登录改密码配置
     */
    public boolean isFirstLoginChangePassword() {
        return firstLoginChangePassword;
    }
}
